;
;		SENDRECV.A86
;
;Christensen protocol routines for MODEM9.xx.
;
;SEND A CP/M FILE
;
SENDFIL:
	MOV	CKSUMFLG,TRUE	;ALWAYS FORCE CHECKSUM MODE INITIALLY ON SEND
	CALL	CKMODM		;REMOVE GARBAGE FROM LINE
SENDFIL1:
	TEST	BATCHFLG,0FFH	;CHECK IF MULTIPLE FILE..
	JNZ	SENDC1
	CALL	ILPRT
	DB	'Ready to send in the batch mode',CR,LF,0
	MOV	SENDFLG,TRUE	;INDICATE SEND FOR BATCH MODE
	MOV	AL,FSTFLG	;IF FIRST TIME THRU..
	OR	AL,AL		;..SCAN THE COMMAND LINE..
	JZ	SENDFIL2
	CALL	TNMBUF		;..FOR MULTIPLE NAMES.
SENDFIL2:
	CALL	SENDFN		;SENDS FILE NAME TO RECEIVER
	JNC	SENDC2		;CARRY SET MEANS NO MORE FILES.
	MOV	BATCHFLG,'B' 	;STOP BATCH ....MODE OPTION.
	MOV	AL,EOT		;FINAL XFER END
	CALL	SEND
	JMP	DONE
;
SENDC1:
	CMP	BYTE PTR .FCB+1,' '
	JNZ	SENDC2
	JMP	BLKFILE

SENDC2:
	CALL	CNREC		;GET NUMBER OF RECORDS
	CALL	OPENFIL
	MOV	DL,80
	CALL	WAITNAK

SENDLP:
	CALL	CKABORT		;WANT TO TERMINATE WHLE SENDING FILE?
	CALL	RDSECT
	JC	SENDEOF
	CALL	INCRSNO
	MOV	ERRCT,1
SENDRPT:
	CALL	CKABORT		;WANT TO TERMINATE WHILE SENDING FILE?
	CALL	SENDHDR
	CALL	SENDSEC
	MOV	AL,CKSUMFLG
	OR	AL,AL
	JNZ	SENDRPT1
	CALL	SENDCRC
	JMPS	SENDRPT2

SENDRPT1:
	CALL	SENDCKS
SENDRPT2:
	CALL	GETACK
	JC	SENDRPT
	JMP	SENDLP
;
SENDEOF:
	MOV	AL,EOT
	CALL	SEND
	CALL	GETACK
	JC	SENDEOF
	JMP	DONE
;
;RECEIVE A FILE
;
RCVFIL:
	MOV	AL,CKSUMDFLT	;GET MODE REQUESTED BY OPERATOR
	MOV	CKSUMFLG,AL	;STORE IT
	CALL	CKMODM		;CATCH ANY GARBAGE CHARACTERS
RCVFIL1:
	MOV	AL,BATCHFLG	;CHECK IF MULT..
	OR	AL,AL		;..FILE MODE.
	JNZ	RCVC1
	MOV	AL,FALSE	;FLAG WHERE TO RETURN..
	MOV	SENDFLG,AL	;..FOR NEXT FILE TRANS.
	CALL	GETFN		;GET THE FILE NAME.
	JNC	RCVC2		;CARRY SET MEANS NO MORE FILES.
	MOV	AL,'B'		;STOP BATCH..
	MOV	BATCHFLG,AL 	;..MODE OPTION.
	JMP	DONE
;
RCVC1:
	MOV	AL,BYTE PTR .FCB+1	;MAKE SURE FILE IS NAMED
	CMP	AL,' '
	JNZ	RECV1A
	JMP	BLKFILE

RECV1A:
	JMP	RCVC3
;
RCVC2:
	CALL	CKCPM2
	CALL	CKBAKUP
RCVC3:
	CALL	ERASFIL
	CALL	MAKEFIL
	MOV	AL,BATCHFLG	;DON'T PRINT MSG IF IN BATCH
	OR	AL,AL
	JZ	RCVFST
	CALL	ILPRTQ
	DB	'File open, ready to receive',CR,LF,0
RCVFST:
	MOV	AL,CKSUMFLG
	OR	AL,AL
	MOV	AL,NAK
	JNZ	RCVFIL2
	MOV	AL,CRC
RCVFIL2:
	CALL	SEND
	MOV	AL,CKSUMFLG
	OR	AL,AL
	JNZ	RCVNAKM		;IF IN CRC MODE
	CALL	ILPRTQ		;THEN SAY SO
	DB	'CRC in effect',CR,LF,0
	JMP	RCVLP

RCVNAKM:
	CALL	ILPRTQ		;ELSE SAY CHECKSUM MODE
	DB	'Checksum in effect',CR,LF,0
RCVLP:
	CALL	RCVSECT
	JC	RCVEOT
	CALL	WRSECT
	CALL	INCRSNO
	CALL	SENDACK
	JMP	RCVLP
;
RCVEOT:
	CALL	WRBLOCK
	CALL	SENDACK
	CALL	CLOSFIL
	JMP	DONE
;	
;SUBROUTINES
;
SENDFN:
	CALL	ILPRTQ
	DB	'Awaiting name NAK',CR,LF,0
	MOV	DL,80
	CALL	WAITNLP
	MOV	AL,ACK		;GOT NAK, SEND ACK
	CALL	SEND
	MOV	BX,OFFSET FILECT
	DEC	BYTE PTR [BX]
	JS	NOMRNM
	MOV	BX,NBSAVE	;GET FILE NAME..
	MOV	DX,OFFSET FCB	;..IN FCB
	MOV	CH,12
	CALL	MOVE
	MOV	NBSAVE,BX
	CALL	SENDNM		;SEND IT
	OR	AL,AL		;CLEAR CARRY
	RET
;
NOMRNM:
	MOV	AL,EOT
	CALL	SEND
	STC
	RET
;
SENDNM:
	PUSH	BX
SENDNM1:
	MOV	DH,11		;COUNT CHARS IN NAME
	MOV	CL,0		;INIT CHECKSUM
	MOV	AL,CL
	MOV	FTYCNT,AL	;INITIATE FILE TYPE COUNT
	MOV	BX,OFFSET FCB+1	;ADDRESS NAME
NAMLPS:
	MOV	AL,BYTE PTR [BX]	;SEND NAME
	AND	AL,07FH		;STRIP HIGH ORDER BIT SO CP/M 2..
	CALL	SEND		;..WON'T SEND R/O FILE DESIGNATION.
	MOV	AL,QFLG		;SHOW NAME IF..
	OR	AL,AL		;..QFLG NOT SET.
	MOV	AL,BYTE PTR [BX]
	JZ	ACKLP
	CALL	FTYTST		;TYPE CHARACTER ETC.
ACKLP:
	PUSH	CX		;SAVE CKSUM
	MOV	CH,1		;WAIT FOR RECEIVER..
	CALL	RECV		;..TO ACKNOWLEDGE..
	POP	CX		;..GETTING LETTER.
	JC	SCKSER
	CMP	AL,ACK
	JNZ	ACKLP
	INC	BX		;NEXT CHAR
	DEC	DH
	JNZ	NAMLPS
	MOV	AL,EOFCHAR	;TELL RECEIVER END OF NAME
	CALL	SEND
	MOV	AL,QFLG
	OR	AL,AL
	JZ	ACKLP1
	CALL	CRLF
ACKLP1:
	MOV	DH,CL		;SAVE CHECKSUM
	MOV	CH,1
	CALL	RECV		;GET CHECKSUM..
	CMP	AL,DH		;..FROM RECEIVER.
	JZ	NAMEOK
SCKSER:	MOV	AL,BDNMCH	;BAD NAME-TELL RECEIVER
	CALL	SEND
	CALL	ILPRTQ
	DB	'Checksum error',CR,LF,0
	MOV	DL,80		;DO HANDSHAKING OVER
	CALL	WAITNLP		;DON'T PRINT "AWAITING NAK" MSG
	MOV	AL,ACK
	CALL	SEND
	JMP	SENDNM1
;
NAMEOK:
	MOV	AL,OKNMCH	;GOOD NAME, TELL RECEIVER
	CALL	SEND
	POP	BX
	RET	
;
GETFN:	MOV	BX,OFFSET FCB
	CALL	INITFCBS+2	;DOES NOT INITIALIZE DRIVE
	CALL	ILPRTQ
	DB	'Awaiting file name',CR,LF,0
GNAMELP:
	CALL	HSNAK
	CALL	GETNM		;GET THE NAME
	CMP	AL,EOT		;IF EOT, THEN NO MORE FILES
	JZ	NOMRNMG
	OR	AL,AL		;CLEAR CARRY
	RET
;
NOMRNMG:
	STC
	RET
;
GETNM:
	PUSH	BX
GETNM1:
	MOV	CL,0		;INIT CHECKSUM
	MOV	AL,CL
	MOV	FTYCNT,AL	;INITIATE COUNT FOR FILE TYPE
	MOV	BX,OFFSET FCB+1
NAMELPG:
	MOV	CH,5
	CALL	RECV		;GET CHAR
	JNC	GETNM3
	CALL	ILPRTQ
	DB	'Time out receiving filename',CR,LF,0
	JMP	GCKSER
;
GETNM3:
	CMP	AL,EOT		;IF EOT, THEN NO MORE FILES
	JNZ	GETNM4
	JMP	GNRET

GETNM4:
	CMP	AL,EOFCHAR	;GOT END OF NAME
	JZ	ENDNAME
	MOV	BYTE PTR [BX],AL	;PUT NAME IN FCB
	MOV	AL,QFLG		;CAN TYPE IT IF NO QFLG
	OR	AL,AL
	JZ	SKPTYP
	CALL	FTYTST
SKPTYP:
	PUSH	CX		;SAVE CKSUM
	MOV	AL,ACK		;ACK GETTING LETTER
	CALL	SEND
	POP	CX
	INC	BX		;GET NEXT CHAR
	MOV	AL,BL		;DON'T LET NOISE...
	CMP	AL,7FH		;..CAUSE OVERFLOW..
	JZ	GCKSER		;..INTO PROGRAM AREA.
	JMP	NAMELPG
;
FTYTST:
	INC	FTYCNT
	CMP	FTYCNT,9	; ARE WE AT THE FILE TYPE?
	JZ	SPCTST		;GO IF SO
ENDSPT:
	MOV	AL,BYTE PTR [BX]
	CMP	AL,' '		;TEST FOR SPACE
	JZ	ENDSPT1
	CALL	TIPE		;TYPE IF NOT
ENDSPT1:
	RET
;
SPCTST:
	MOV	AL,BYTE PTR [BX]
	CMP	AL,' '		;TEST FOR SPACE IN FIRST FILE TYPE BYTE
	JZ	ENDSPT1		;DON'T OUTPUT PERIOD IF SPACE
				; MJM 9.01.05 WAS JMPS
	MOV	AL,'.'	
	CALL	TIPE
	JMP	ENDSPT		;OUTPUT FIRST FILE TYPE BYTE
;
ENDNAME:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	ENDNAME1
	CALL	CRLF
ENDNAME1:
	MOV	AL,CL		;SEND CHECKSUM
	CALL	SEND
	MOV	CH,1
	CALL	RECV		;CHECKSUM GOOD?
	CMP	AL,OKNMCH	;YES IF OKNMCH SENT..
	JZ	GNRET		;..ELSE DO OVER.
GCKSER:
	MOV	BX,OFFSET FCB	;CLEAR FCB (EXCEPT DRIVE)..
	CALL	INITFCBS+2 	;..SINCE IT MIGHT BE DAMAGED..
	CALL	ILPRTQ
	DB	CR,LF,'++ Checksum error ++',CR,LF,0
	CALL	HSNAK		;DO HANDSHAKING OVER
	JMP	GETNM1
;
GNRET:
	POP	BX
	RET
;
HSNAK:
	MOV	DL,180		;3-MINUTE MAXIMUM WAIT FOR A FILE NAME
HSNAK1:
	CALL	CKABORT		;WANT TO ABORT?
	MOV	AL,NAK		;SEND NAK UNTIL RECEIVING ACK
	CALL	SEND
	MOV	CH,1		;WAIT UP TO 1 SECOND FOR A CHARACTER
	CALL	RECV
	CMP	AL,ACK		;'ACK' IS WHAT WE WERE WAITING FOR
	JNZ	HSNAK2
	RET

HSNAK2:
	DEC	DL		;ONE LESS TO TRY
	JNZ	HSNAK1
	JMP	ABORT		;TIMED OUT, ABORT BACK TO COMMAND LINE
;
TNMBUF:
	MOV	AL,FALSE	;CALL FROM SENDFIL ONLY ONCE.
	MOV	FSTFLG,AL
	MOV	FILECT,AL
	CALL	SCAN
	MOV	BX,OFFSET NAMEBUF
	MOV	NBSAVE,BX	;SAVE ADDR OF 1ST NAME
TNLP1:
	CALL	TRTOBUF
	MOV	BX,OFFSET FCB
	MOV	DX,OFFSET FCBBUF
	CALL	CPMLINE		;PARSE NAME TO CP/M FORMAT
TNLP2:
	CALL	MFNAME		;SEARCH FOR NAMES (* FORMAT)
	JC	NEXTNM
	MOV	AL,BYTE PTR .FCB+10	;IF CP/M 2 $SYS FILE..
	AND	AL,80H		;..DON'T SEND
	JNZ	TNLP2
	MOV	BX,NBSAVE	;GET NAME
	MOV	DX,OFFSET FCB	;MOVE IT TO FCB
	XCHG	BX,DX
	MOV	CH,12
	CALL	MOVE
	XCHG	BX,DX
	MOV	NBSAVE,BX	;ADDR OF NEXT NAME
	MOV	BX,OFFSET FILECT	;COUNT FILES FOUND
	INC	BYTE PTR [BX]
	JMP	TNLP2
;
NEXTNM:
	MOV	BX,OFFSET SNAMECT ;COUNT NAMES FOUND
	DEC	BYTE PTR [BX]
	JNZ	TNLP1
	MOV	BX,OFFSET NAMEBUF  ;SAVE START OF BUFFER
	MOV	NBSAVE,BX
	MOV	AL,FILECT
	CMP	AL,65		;NO MORE THAN 64 TRANSFERS
	JNC	NEXTNM1
	RET

NEXTNM1:
	MOV	AL,64	;ONLY X'FER FIRST 64
	MOV	FILECT,AL
	RET
;
;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE)
;AFTER LAST NAME
;
SCAN:
	PUSH	BX
	MOV	BX,OFFSET SNAMECT
	MOV	BYTE PTR [BX],0
	MOV	BX,OFFSET CMDBUF+1  ;FIND END OF CMD LINE..
	MOV	CL,BYTE PTR [BX]  ;..AND PUT SPACE THERE.
	MOV	CH,0
	MOV	BX,OFFSET CMDBUF+2
	ADD	BX,CX
	MOV	BYTE PTR [BX],20H
	MOV	BX,OFFSET CMDBUF+1
	MOV	CH,BYTE PTR [BX]
	INC	CH
	INC	CH
SCANLP1:
	INC	BX
	DEC	CH
	JZ	DNSCAN
	MOV	AL,BYTE PTR [BX]
	CMP	AL,20H
	JNZ	SCANLP1
SCANLP2:
	INC	BX		;EAT EXTRA SPACES
	DEC	CH
	JZ	DNSCAN
	MOV	AL,BYTE PTR [BX]
	CMP	AL,20H
	JZ	SCANLP2
	MOV	BGNMS,BX	;SAVE START OF NAMES IN CMDBUF
	INC	CH
	DEC	BX
SCANLP3:
	INC	BX
	DEC	CH
	JZ	DNSCAN
	MOV	AL,BYTE PTR [BX]
	CMP	AL,20H
	JNZ	SCANLP3
	MOV	AL,SNAMECT	;COUNTS NAMES
	INC	AL
	MOV	SNAMECT,AL
SCANLP4:
	INC	BX		;EAT SPACES
	DEC	CH
	JZ	DNSCAN
	MOV	AL,BYTE PTR [BX]
	CMP	AL,20H
	JZ	SCANLP4
	JMP	SCANLP3
;
DNSCAN:
	MOV	BYTE PTR [BX],20H	;SPACE AFTER LAST CHAR
	POP	BX
	RET
;
;PLACES NEXT NAME IN BUFFER SO 'CPMLINE' MAY PARSE IT
;
TRTOBUF:
	MOV	BX,BGNMS
	MOV	CH,0
	MOV	DX,OFFSET FCBBUF+2
TBLP:
	MOV	AL,BYTE PTR [BX]
	CMP	AL,20H
	JZ	TRBFEND
	XCHG	BX,DX
	MOV	BYTE PTR [BX],AL
	XCHG	BX,DX
	INC	BX
	INC	DX
	INC	CH		;COUNT CHARS IN NAME
	JMP	TBLP
;
TRBFEND:
	INC	BX
	MOV	AL,BYTE PTR [BX]	;EAT EXTRA SPACES
	CMP	AL,20H
	JZ	TRBFEND
	MOV	BGNMS,BX
	MOV	BX,OFFSET FCBBUF+1 	;PUT # CHARS BEFORE NAME
	MOV	BYTE PTR [BX],CH
	RET
;
RCVSECT:
	MOV	AL,1
	MOV	ERRCT,AL
RCVRPT:
	CALL	CKABORT		;WANT TO STOP RECEIVING FILE?
	MOV	AL,QFLG
	OR	AL,AL
	JZ	RCVSQ
	CALL	ILPRT
	DB	CR,'Awaiting # ',0
	PUSH	BX		;SAVE IT
	MOV	BX,SECTNO	;GET SECTOR NUMBER
	INC	BX		;BUMP IT
	CALL	DECOUT		;PRINT SECTOR NUMBER IN DECIMAL
	CALL	ILPRT
	DB	' (', 0
	CALL	DHXOUT		;16 BIT HEX CONVERSION & OUTPUT
	CALL	ILPRT
	DB	'H)',0
	MOV	AL,BL		;ONLY LOW BYTE USED BY PROGRAM
	POP	BX		;RESTORE IT
RCVSQ:				;WAIT FOR SOH OR EOT
	MOV	CH,10		;10 SECONDS
	CALL	RECV
	JNC	RCVSQ1
	JMP	RCVSTOT

RCVSQ1:
	CMP	AL,SOH
	JNZ	RCVSQ2
	JMP	RCVSOH

RCVSQ2:
	OR	AL,AL
	JZ	RCVSQ
	CMP	AL,EOT
	STC
	JNZ	RCVSQ3
	RET

RCVSQ3:
	MOV	CH,AL
	MOV	AL,QFLG
	OR	AL,AL
	JZ	RCVSERR
RCVSEH:
	MOV	AL,CH
	CALL	CRLF
	CALL	HEXO
	CALL	ILPRT
	DB	'H received not SOH - ',0
RCVPRN:
	CALL	SHOWERR		;DISPLAY ERROR COUNT
RCVSERR:
	MOV	CH,1		;WAIT FOR 1 SEC..
	CALL	RECV		;..WITH NO CHARS
	JNC	RCVSERR 	;LOOP UNTIL SENDER DONE
	CALL	CKABORT		;WANT TO STOP RECEIVING NOW?
	MOV	AL,CKSUMFLG	;GET CHECKSUM FLAG
	OR	AL,AL		;CRC IN EFFECT?
	MOV	AL,NAK		;PUT NAK IN ACCUM
	JNZ	RCVSER2		;NO, SEND THE NAK
	MOV	AL,FIRSTME 	;GET FIRST TIME SWITCH
	OR	AL,AL		;HAS FIRST SOH BEEN RECEIVED?
	MOV	AL,NAK		;PUT NAK IN ACCUM
	JZ	RCVSER2		;YES, THEN SEND NAK
	MOV	AL,CRC		;TELL SENDER CRC IS IN EFFECT
RCVSER2:
	CALL	SEND		;..THE NAK or CRC request
	MOV	AL,ERRCT	;ABORT IF..
	INC	AL		;..WE HAVE REACHED..
	MOV	ERRCT,AL	;..THE ERROR..
	CMP	AL,ERRLIM	;..LIMIT?
	JNC	RCVSER3
	JMP	RCVRPT		;..NO, TRY AGAIN

RCVSER3:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	RCVSABT
RCVCKQ:
	CALL	CKQUIT
	JNZ	RCVSABT
	JMP	RCVSECT

RCVSABT:
	CALL	CLOSFIL		;CLOSE THE PARTIAL FILE
	CALL	NOASK		;DELETE PARTIAL FILE
	CALL	ILPRT
	DB	CR,LF,LF
	DB	'++ File receive cancelled and unfinished file deleted ++'
	DB	BELL,CR,LF,0
	JMP	DONETCA
;
RCVSTOT:
	MOV	AL,QFLG
	OR	AL,AL
RCVSPT:	CALL	ILPRT
	DB	CR,LF,'++ Timeout ',0
	CALL	SHOWERR
RCVSCRC:
	CALL	RCVSCRC2
	JMP	RCVSERR
;
;ROUTINE WILL SWITCH FROM CRC TO CHECKSUM IF ERCNT REACHES ERRCRC
;AND FIRSTME IS TRUE
;
RCVSCRC2:
	MOV	AL,ERRCT
	CMP	AL,ERRCRC
	JNZ	RCVSCRC3
	MOV	AL,FIRSTME
	OR	AL,AL
	JZ	RCVSCRC3
	MOV	AL,CKSUMFLG
	OR	AL,AL
	JNZ	RCVSCRC3
	NOT	AL
	MOV	CKSUMFLG,AL
	MOV	CKSUMDFLT,AL
	CALL	ILPRTQ
	DB	'++ Switching to Checksum mode ++',CR,LF
	DB	'++ Sender may not be CRC capable ++',CR,LF,BELL,0
RCVSCRC3:
	RET
;
;Got SOH - get block #, block # complemented
;
RCVSOH:
	XOR	AL,AL		;ZERO ACCUM
	MOV	FIRSTME,AL	;INDICATE FIRST SOH RECV'D
	MOV	CH,1		;TIMEOUT = 1 SEC
	CALL	RECV		;GET SECTOR
	JNC	RCVSOH1
	JMP	RCVSTOT		;GOT TIMEOUT

RCVSOH1:
	MOV	DH,AL
	MOV	CH,1
	CALL	RECV
	JNC	RCVSOH2
	JMP	RCVSTOT

RCVSOH2:
	NOT	AL
	CMP	AL,DH
	JZ	RCVDATA
	MOV	AL,QFLG
	OR	AL,AL
	JNZ	RCVBSE
	JMP	RCVSERR

RCVBSE:
	CALL	ILPRT
	DB	CR,LF,'++ Bad sector # in Header ',0
	JMP	RCVPRN
;
RCVDATA:
	MOV	AL,DH
	MOV	RCVSNO,AL
	MOV	AL,1
	MOV	DATAFLG,AL
	MOV	CL,0
	CALL	CLRCRC		;CLEAR CRC COUNTER
	MOV	BX,OFFSET 80H
RCVCHR:
	MOV	CH,1
	CALL	RECV
	JNC	RCVCHR1
	JMP	RCVSTOT

RCVCHR1:
	MOV	BYTE PTR [BX],AL
	INC	BL
	JNZ	RCVCHR
	MOV	AL,CKSUMFLG
	OR	AL,AL
	JZ	RCVCRC
	MOV	DH,CL		; 9.01.02 MJM 7/8/83
	XOR	AL,AL
	MOV	DATAFLG,AL
	MOV	CH,1
	CALL	RECV
	JNC	RCVCHR2
	JMP	RCVSTOT

RCVCHR2:
	CMP	AL,DH
	JNZ	RCVCERR
CHKSNUM:
	MOV	AL,RCVSNO
	MOV	CH,AL
	MOV	AX,SECTNO
	CMP	AL,CH
	JZ	RECVACK
	INC	AL
	CMP	AL,CH
	JZ	CHKSNUM1
	JMP	ABORT

CHKSNUM1:
	RET
;
RCVCRC:
	MOV	DL,2		;NUMBER OF CRC BYTES
RCVCRC2:
	MOV	CH,1
	CALL	RECV
	JNC	RCVCRC3
	JMP	RCVSTOT

RCVCRC3:
	DEC	DL
	JNZ	RCVCRC2
	CALL	CHKCRC
	OR	AL,AL
	JZ	CHKSNUM
	MOV	AL,QFLG
	OR	AL,AL
	JNZ	RCVCRER
	JMP	RCVSERR

RCVCRER:
	CALL	ILPRT
	DB	CR,LF,'++ CRC error ',0
	JMP	RCVPRN
;
RCVCERR:
	MOV	AL,QFLG
	OR	AL,AL
	JNZ	RCVCPR
	JMP	RCVSERR

RCVCPR:
	CALL	ILPRT
	DB	CR,LF,'++ Checksum error ',0
	JMP	RCVPRN
;
RECVACK:
	CALL	SENDACK
	JMP	RCVSECT
;
SENDACK:
	MOV	AL,ACK
	CALL	SEND
	RET
;
SENDHDR:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	SENDHNM
	CALL	ILPRT
	DB	CR,'Sending # ',0
	PUSH	BX
	MOV	BX,SECTNO	;GET SECTOR NUMBER
	CALL	DECOUT		;PRINT IT IN DECIMAL
	CALL	ILPRT
	DB	' (',0
	CALL	DHXOUT		;16 BIT HEX CONVERSION & OUTPUT
	CALL	ILPRT
	DB	'H)',0
	POP	BX
SENDHNM:
	MOV	AL,SOH
	CALL	SEND
	MOV	AX,SECTNO
	CALL	SEND
	MOV	AX,SECTNO
	NOT	AL
	CALL	SEND
	RET
;
SENDSEC:
	MOV	AL,1
	MOV	DATAFLG,AL
	MOV	CL,0
	CALL	CLRCRC
	MOV	BX,OFFSET 80H
SENDC:
	MOV	AL,BYTE PTR [BX]
	CALL	SEND
	INC	BL
	JNZ	SENDC
	XOR	AL,AL
	MOV	DATAFLG,AL
	RET
;
SENDCKS:
	MOV	AL,CL
	CALL	SEND
	RET
;
SENDCRC:
	CALL	FINCRC
	MOV	AL,DH
	CALL	SEND
	MOV	AL,DL
	CALL	SEND
	XOR	AL,AL
	RET
;
;
;After a record is sent, a character is returned telling if it was re-
;ceived properly or not.  An ACK allows the next record to be sent.  A
;NAK sends an error message and the current record is again repeated.
;This occurs until the error limit has been reached.  If the first NAK
;is missed, it waits up to 12 seconds before declaring a 2nd error.
;This insures there is no collision with the station attempting to send
;the NAK, since it waits only 10 seconds.
;
GETACK:
	MOV	CH,12		;12 SECONDS
	CALL	RECVDG		;WAIT FOR ACK OR NAK
	JNC	GETACK1
	JMP	GETATOT		;NO CHARACTER, TIMED OUT

GETACK1:
	CMP	AL,ACK
	JNZ	NOTACK
	RET			;IF ACK RETURN AND SEND NEXT RECORD

NOTACK:
;
;If the ACKNAK option is FALSE it will resend the sector when any char-
;acter other than ACK is received (including NAK).
;
	MOV	CH,AL
	MOV	AL,NAKONLY
	OR	AL,AL
	JZ	ALLOTH
	CMP	AL,NAK		;WAS IT AN AUTHENTIC 'NAK'?
	JNZ	GETACK		;IGNORE IF NEITHER 'ACK' NOR 'NAK'
				;WILL EVENTUALLY TIME OUT
ALLOTH:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	ACKERR
	CALL	ILPRT
	DB	CR,LF,'++ ',0
	MOV	AL,CH
	CMP	AL,NAK		;IS IT A 'NAK'?
	JZ	GETACK2		;SHOW 'NAK' IN THAT CASE
	CALL	HEXO
	MOV	AL,'H'
	CALL	TIPE
	JMP	GETACK3
GETACK2:
	CALL	ILPRT
	DB	'NAK',0	
GETACK3:
	CALL	ILPRT		;PRINT THE ERROR MESSAGE
	DB	' received not ACK - ',0
	CALL	SHOWERR		;SHOW THE ERROR NUMBER
ACKERR:
	MOV	AL,ERRCT
	INC	AL
	MOV	ERRCT,AL
	DEC	AL
	CMP	AL,ERRLIM
	JNC	ACKERR1
	RET

ACKERR1:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	CSABORT
GACKV:
	CALL	CKQUIT
	STC
	JNZ	CSABORT
	RET
CSABORT:
	CALL	ERXIT
	DB	CR,LF,'Can''t send sector -- Aborting',CR,LF,'$'
GETATOT:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	ACKERR
	CALL	ILPRT
	DB	CR,LF,'++ Timeout on ACK - ',0
	CALL	SHOWERR		;DISPLAY ERROR COUNT
	JMP	ACKERR
;
CKABORT:
	MOV	AL,QFLG
	OR	AL,AL
	JNZ	CKABGO
	RET

CKABGO:
	CALL	STAT
	JNZ	CKABGO1
	RET

CKABGO1:
	CALL	KEYIN
	CMP	AL,CAN
	JZ	ABORT
	RET

ABORT:	
	MOV	CH,1
	CALL	RECV
	JNC	ABORT
	MOV	AL,CAN
	CALL	SEND
ABORTW:
	MOV	CH,1
	CALL	RECV
	JNC	ABORTW
	MOV	AL,' '
	CALL	SEND
	MOV	AL,'B'     	;TURN MULTI-FILE MODE..
	MOV	BATCHFLG,AL	;..OFF SO ROUTINE ENDS.
	MOV	AL,OPTION	;RECEIVING A FILE NOW?
	CMP	AL,'R'
	JNZ	ABORTW1
	JMP	RCVSABT		;IF YES, CANCEL THE UNFINISHED FILE

ABORTW1:
	CALL	ILPRT
 	DB	CR,LF,LF,'++ File send cancelled ++',CR,LF,BELL,0
	JMP	DONETCA
;
INCRSNO:
	INC	SECTNO		; INCREMENT SECTOR NUMBER
	MOV	AX,SECTNO	; NEED IT IN LOW BYTE, DON'T CARE ABOUT HIGH
	RET
;
;---->	RECV: Receive a character
;
;Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage
;characters on the line. For example, having just sent a sector, calling
;RECVDG will delete any line noise induced characters LONG before the
;ACK/NAK would be received.
;
RECVDG:
	CALL	CKMODM		;CATCH ANY GARBAGE CHARACTERS
RECV:
	PUSH	DX
MSEC:
	PUSH	BX
	MOV	BX,OFFSET 5000
	CALL	FIXCNT
	PUSH	BX
	POP	DX
	POP	BX
	CALL	CKABORT
MWTI:
	CALL	RCVREADY
	JZ	MCHAR
	DEC	DL
	JNZ	MWTI
	DEC	DH
	JNZ	MWTI
	DEC	CH
	JNZ	MSEC
	POP	DX
	STC
	RET
;
MCHAR:
	CALL	INMODDATP
	POP	DX
	PUSH	AX
	CALL	UPDCRC      	;CALCULATE CRC
	ADD	CL,AL
	MOV	AL,RSEEFLG
	OR	AL,AL
	JZ	MONIN
	MOV	AL,VSEEFLG
	OR	AL,AL
	JNZ	NOMONIN
	MOV	AL,DATAFLG
	OR	AL,AL
	JZ	NOMONIN
MONIN:
	POP	AX
	PUSH	AX
	CALL	SHOW
NOMONIN:
	POP	AX
	OR	AL,AL
	RET
;
SEND:
	PUSH	AX
	MOV	AL,SSEEFLG
	OR	AL,AL
	JZ	MONOUT
	MOV	AL,VSEEFLG
	OR	AL,AL
	JNZ	NOMONOT
	MOV	AL,DATAFLG
	OR	AL,AL
	JZ	NOMONOT
MONOUT:
	POP	AX
	PUSH	AX
	CALL	SHOW
NOMONOT:
	POP	AX
	PUSH	AX
	CALL	UPDCRC		;CALCULATE CRC
	ADD	CL,AL
SENDW:
	CALL	SENDREADY
	JNZ	SENDW
	POP	AX
	CALL	OUTMODDATP
	RET
;
WAITNAK:
	CALL	ILPRTQ
	DB	'Awaiting initial NAK',CR,LF,0
WAITNLP:
	CALL	CKABORT
	MOV	CH,1
	CALL	RECV
	CMP	AL,NAK
	JNZ	WAITNLP1
	RET

WAITNLP1:
	CMP	AL,CRC		;CRC REQUEST?
	JZ	WAITCRC		;YES, GO SET CRC FLAG
	CMP	AL,CAN
	JNZ	WAITNLP2
	JMP	ABORT

WAITNLP2:
	DEC	DL
	JNZ	WAITNLP
	JMP	ABORT
;
WAITCRC:
	CALL	ILPRTQ
	DB	'CRC request received',CR,LF,0
	XOR	AL,AL
	MOV	CKSUMFLG,AL
	RET
;
;RETURNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN
;NO QUESTIONS ASKED, JUST QUIT
;
CKQUIT:
	MOV	AL,BATCHFLG
	OR	AL,AL
	JNZ	CKQTASK		;ASK FOR RETRY
	INC	AL		;RESET ZERO FLG
	RET
;
CKQTASK:
	MOV	ERRCT,1
	CALL	ILPRT
	DB	CR,LF,'Multiple errors encountered.',CR,LF
	DB	'Type Q to quit, R to retry:  ',BELL,0
	CALL	KEYIN
	CALL	CRLF
	CALL	UCASE		;INSTEAD OF "ANI 5FH"
	CMP	AL,'R'
	JZ	CKQTASK1
	CMP	AL,'Q'
	JNZ	CKQUIT
	OR	AL,AL
CKQTASK1:
	RET
;
;Get the error count and display on CRT
;
SHOWERR:
	PUSH	BX		;SAVE THE CURRENT ADDRESS
	MOV	BL,ERRCT	;GET THE CURRENT ERROR NUMBER
	MOV	BH,0		;ONLY A 8-BIT NUMBER, NOW IN 'L' REG.
	CALL	DECOUT		;DISPLAY THE ERROR IN DECIMAL
	POP	BX		;RESTORE THE CURRENT ADDRESS
	CALL	ILPRT
	DB	' ++',CR,LF,0	;FINISH THE ERROR MESSAGE
	RET
;
ERXIT:
	POP	DX
	CALL	PRTMSG
	MOV	AL,BELL
	CALL	TIPE
	MOV	AL,BATCHFLG
	OR	AL,AL
	JZ	ERXIT1
	JMP	DONETCA

ERXIT1:
	MOV	AL,'Q'		;RESET QFLG
	MOV	QFLG,AL
	JMP	ABORT		;ABORT OTHER COMPUTER
;
DONE:
	MOV	AL,BATCHFLG
	OR	AL,AL
	JZ	DONE1
	JMP	DONETC

DONE1:
	MOV	AL,QFLG
	OR	AL,AL
	JZ	NMSTRNS
	MOV	CH,12		;ZERO OUT FTRNMSG
	MOV	BX,OFFSET FTRNMSG
ZEROLP:
	MOV	BYTE PTR [BX],' ' ; mjm 9.01.05 FIX BATCH NAME REPORT
	INC	BX
	DEC	CH
	JNZ	ZEROLP
	MOV	CH,12		;PUT FILE NAME IN FTRNMSG
	MOV	BX,OFFSET FCB+1		
	MOV	DX,OFFSET FTRNMSG
LOADMSG:
	MOV	AL,4	;START OF FILE TYPE?
	CMP	AL,CH
	JZ	PERIOD		;PUT IN PERIOD IF SO
	MOV	AL,BYTE PTR [BX]	
	CMP	AL,' '		;DON'T PUT IN SPACE
	JZ	SKPSP	
	XCHG	BX,DX
	MOV	BYTE PTR [BX],AL	;STORE IN FTRNMSG
	XCHG	BX,DX
	INC	DX
SKPSP:
	INC	BX
	DEC	CH
	MOV	AL,CH
	OR	AL,AL		;END OF FILE NAME?
	JZ	FTRNMSG0	;DISPLAY FILE NAME
	JMP	LOADMSG		;LOOP FOR ANOTHER CHARACTER
;
PERIOD:
	MOV	AL,BYTE PTR [BX]
	CMP	AL,' '		;IS FILE TYPE EMPTY?
	JZ	FTRNMSG0	;GO IF SO
	MOV	AL,'.'		;ELSE PUT PERIOD IN MESSAGE
	XCHG	BX,DX
	MOV	BYTE PTR [BX],AL
	XCHG	BX,DX
	INC	DX
	DEC	CH
	JMP	LOADMSG	
;
FTRNMSG0:
	CALL	ILPRT
	DB	CR,LF
FTRNMSG	RB	12
	DB	0
	CALL	ILPRT
	DB	' Transferred',CR,LF,LF,0
NMSTRNS:
	MOV	AL,BYTE PTR .FCB	;SAVE DRIVE NO.
	MOV	DISKNO,AL
	MOV	BX,OFFSET FCB	;BLANK OUT FILE CONTROL BLOCKS
	CALL	INITFCBS
	MOV	AL,DISKNO	;PUT DRIVE NUMBER BACK
	MOV	BYTE PTR .FCB,AL
	MOV	BX,OFFSET RESTSN ;RESTORE SECTORE NUMBERS..
	MOV	DX,OFFSET SECTNOB ;..FOR NEW FILE TRANSFER.
	MOV	CH,OFFSET SECTNOE-OFFSET SECTNOB ;ROUTINE ALSO DONE IN MENU.
	CALL	MOVE
	CALL	CKMODM		;CATCH ANY GARBAGE CHARACTERS
	MOV	AL,SENDFLG	;GOES TO EITHER SEND OR..
	OR	AL,AL		;..RECEIVE FILE, DEPENDING..
	JZ	NMSTRNS1
	JMP	SENDFIL1	;..UPON WHICH ROUTINE SET..

NMSTRNS1:
	JMP	RCVFIL1		;..THE FLAG IN MULTI-FILE MODE.
;
DONETC:
	CALL	CKABORT		;SLIGHT DELAY FOR NEXT MESSAGE
	CALL	ILPRT
	DB	CR,LF,'All transfers completed',CR,LF,BELL,0
DONETCA:
	MOV	AL,TRUE
	MOV	FIRSTME,AL	;SET FIRST-TIME FLAG
	MOV	FSTFLG,AL	;RESET MULTIFILE TRANS
	MOV	NFILFLG,AL	;..USED IN TERMINAL ROUTINE
	NOT	AL
	MOV	SAVEFLG,AL	;STOP MEMORY SAVE IN TERM ROUTINE
	MOV	LISTMOR,AL	;STOP ANY BUFFERED OUTPUT TO PRINTER
	MOV	BX,OFFSET BOTTRAM	;RESET PRINTER BUFFER POINTERS
	MOV	HLSAVE1,BX
	MOV	HLSAVE2,BX
	MOV	AL,TERMFLG	;SEE IF RETURN TO..
	OR	AL,AL		;..TERMINAL MODE..
	JNZ	DONETCA1	;..AFTER X'FER.
	CALL	ILPRT
	DB	CR,LF,'** Entering terminal mode **',CR,LF,LF,BELL,0
	JMP	TERM

DONETCA1:
	JMP	MENU
;
;Shows the time to transfer a file at various baud rates
;
SENDTIM:
	CALL	ILPRT	        ;PRINT:
	DB	'File open:  ',0
	MOV	BX,RCNT		;GET RECORD COUNT.
	CALL	DECOUT		;PRINT DECIMAL NUMBER OF RECORDS
	CALL	ILPRT
	DB	' (',0
	CALL	DHXOUT		;NOW PRINT SIZE IN HEX.
	CALL	ILPRT
	DB	' Hex) Records',CR,LF
	DB	'Send time:  ',0
	MOV	AL,MSPEED		;GET THE SPEED INDICATOR
	MOV	DH,0
	MOV	DL,AL		;SET UP FOR TABLE ACCESS
	MOV	BX,OFFSET BTABLE	;POINT TO BAUD FACTOR TABLE
	ADD	BX,DX		;INDEX TO PROPER FACTOR
	ADD	BX,DX
	MOV	DL,BYTE PTR [BX];FACTOR IN DE
	INC	BX
	MOV	DH,BYTE PTR [BX]
	MOV	BX,RCNT		;GET # OF RECORDS
	CALL	DIVHLDE		;DIVIDE HL BY VALUE IN A (RECORDS/MIN)	
	PUSH	BX
	MOV	BX,CX
	CALL	DECOUT		;PRINT THE MINUTES PORTION
	CALL	ILPRT
	DB	' mins, ',0
	MOV	BX,OFFSET SECTBL ;POINT TO DIVISORS FOR SECONDS
	MOV	DX,0		;   CALCULATION
	MOV	AL,MSPEED	;GET INDEX FOR BAUD RATE
	MOV	DL,AL
	ADD	BX,DX		;INDEX INTO TABLE
	MOV	AL,BYTE PTR [BX];GET MULTIPLIER = (SEC/REC) x 16
	POP	BX		;GET REMAINDER
	CALL	MULHLA		;MULTIPLY THE 'HL' x 'A'
	CALL	SHFTHL		;DIVIDE BY 16
	CALL	SHFTHL
	CALL	SHFTHL
	CALL	SHFTHL	
	MOV	BH,0
	CALL	DECOUT		;PRINT THE SECONDS PORTION
	CALL	ILPRT
	DB	' secs at ',0
	CALL	BAUDPRT
	CALL	ILPRT
        DB    'To cancel use ctrl-X',CR,LF,0
	RET
;
; CORRECTED BY M.J. MELLINGER FOR 9.01.05 11/25/83
BTABLE	DW	5,13,25,48,96,192,384,0	;RECORDS/MIN FOR 110-9600 BAUD
SECTBL	DB	192,74,38,20,11,5,3,0
;
;	
;---->  DIVHLDE: DIVIDES 'HL' BY VALUE IN 'DE', 
;	UPON EXIT: 'BC'=QUOTIENT,'L'=REMAINDER
;
DIVHLDE:
	PUSH	DX		;SAVE DIVISOR
;	MOV	AL,DL
;	NOT	AL		;NEGATE DIVISOR
;	MOV	DL,AL
;	MOV	AL,DH
;	NOT	AL
;	MOV	DH,AL
;	INC	DX		;DE IS NOW TWOS COMPLEMENTED
	NEG	DX
	MOV	CX,0		;INITIATE QUOTIENT
DIVL1:
	ADD	BX,DX		;SUBTRACT DIVISOR FROM DIVIDEND
	INC	CX		;INCREASE QUOTIENT
	JC	DIVL1		;LOOP UNTIL SIGN CHANGES
	DEC	CX		;ADJUST QUOTIENT
	POP	DX		;RETRIEVE DIVISOR
	ADD	BX,DX		;ADJUST REMAINDER
	RET

;
;---->  MULHLA:  MULTIPLY THE VALUE IN 'HL' BY THE VALUE IN 'A'
;	        RETURN WITH ANSWER IN 'HL'
;
MULHLA:
	XCHG	BX,DX		;MULTIPLICAND TO DE
	MOV	BX,OFFSET 0	;INITIALIZE PRODUCT
	INC	AL		;ADJUST MULTIPLIER
MULLP:
	DEC	AL
	JNZ	MULLP1
	RET

MULLP1:
	ADD	BX,DX
	JMPS	MULLP
;
;  SHIFT 'HL' REGISTER PAIR ONE BIT TO THE RIGHT
;
SHFTHL:
	CLC		;CLEAR THE CARRY
	RCR	BX,1
	RET
;
;****************************************************************
;*								*
;*   CRCSUBS (Cyclic Redundancy Code Subroutines) version 1.20	*
;*   8080 Mnemonics						*
;*								*
;*     These subroutines will compute and check a true 16-bit	*
;*   Cyclic Redundancy Code for a message of arbitrary length.	*
;*								*
;*     The use of this scheme will guarantee detection of all	*
;*   single and double bit errors, all  errors  with  an  odd	*
;*   number  of  error bits, all burst errors of length 16 or	*
;*   less, 99.9969% of all 17-bit error bursts, and  99.9984%	*
;*   of  all  possible  longer  error bursts.  (Ref: Computer	*
;*   Networks, Andrew S.  Tanenbaum, Prentiss-Hall, 1981)	*
;*								*
;*   Designed & coded by Paul Hansknecht, June 13, 1981		*
;*								*
;*   Copyright (c) 1981, Carpenter Associates			*
;*		    Box 451					*
;*		    Bloomfield Hills, MI 48013			*
;*		    313/855-3074				*
;*								*
;*   This program may be freely reproduced for non-profit use.	*
;*								*
;****************************************************************
;
;
CLRCRC:			;RESET CRC ACCUMULATOR FOR A NEW MESSAGE.
	MOV	CRCVAL,0
	RET
;
UPDCRC:			;UPDATE CRC ACCUMULATOR USING BYTE IN (A).
	PUSH	AX
	PUSH	CX
	PUSH	BX
	MOV	CH,8
	MOV	CL,AL
	MOV	BX,CRCVAL
UPDLOOP:
	ROL	CL,1
;	MOV	AL,CL
;	ROL	AL,1
;	MOV	CL,AL
	RCL	BX,1
	JNC	SKIPIT
	XOR	BX,1021H
SKIPIT:
	DEC	CH		;AND XOR 05H FOR XOR 21H IN THE ADJACENT CODE
	JNZ	UPDLOOP
	MOV	CRCVAL,BX
	POP	BX
	POP	CX
	POP	AX
	RET
;
FINCRC:				;FINISH CRC CALCULATION FOR OUTPUT MESSAGE
	PUSH	AX
	XOR	AL,AL
	CALL	UPDCRC
	CALL	UPDCRC
	MOV	DX,CRCVAL
	POP	AX
	RET
;
CHKCRC:				;CHECK CRC BYTES OF RECEIVED MESSAGE
	MOV	AX,CRCVAL
	OR	AL,AH
	JZ	CHKCRCRT
	MOV	AL,0FFH
CHKCRCRT:
	RET
;
CRCVAL	DW	0
;
